use std::{
    borrow::BorrowMut,
    cell::RefCell,
    fmt::format,
    io::ErrorKind,
    ops::{Add, Deref, Sub},
    ptr::null,
};

use super::{expr::*, statements::*, syntaxResult::SyntaxResult, token::*};

pub struct VisitorPrettyPrinter {
    //prefix:RefCell<String>,
    currentLayer: RefCell<usize>,
}
#[allow(non_snake_case)]
impl StmtVisit<String> for VisitorPrettyPrinter {
    fn visitExpressionStmt(&self, expr: &ExpressionStmt) -> Result<String, SyntaxResult> {
        self.print(&expr.expression)
    }

    fn visitPrinterStmt(&self, expr: &PrinterStmt) -> Result<String, SyntaxResult> {
        let name = self.prerry("PrinterStmt".to_string());
        self.addLayer();

        let result = self.parenTheSize(&name.to_string(), &[&expr.expression]);
        self.decLayer();

        Ok(result)
        //self.print(&expr.expression)
    }

    fn visitVariableStmt(&self, expr: &VariableDeclarationStmt) -> Result<String, SyntaxResult> {
        //self.print(expr.initializer.as_ref().unwrap())

        let name = self.prerry("VariableDeclarationStmt".to_string());
        self.addLayer();

        let kind = self.prerry(format!("VariableName:'{}'", expr.name.as_string()));
        let result = if expr.initializer.is_some() {
            self.parenTheSize(&"".to_string(), &[&expr.initializer.as_ref().unwrap()])
        } else {
            self.prerry("initializer:nil".to_string())
        };

        self.decLayer();

        //Err(SyntaxResult::RuntimeError(&expr.name,"Error Variable Declaration!"))
        Ok(format!("{name}{kind}{result}"))
    }

    fn visitBlockStmt(&self, expr: &BlockStmt) -> Result<String, SyntaxResult> {
        let names = self.prerry("BlockStmts".to_string());
        self.addLayer();
        let kind = self.prerry(format!("SyntaxKind:{:?}", SyntaxKind::OpenBrace));
        let mut result = String::new();
        for statement in &expr.statements {
            result = format!("{result}{}", self.execute(statement)?);
        }
        let kind2 = self.prerry(format!("SyntaxKind:{:?}", SyntaxKind::CloseBrace));
        self.decLayer();

        Ok(format!("{names}{kind}{result}{kind2}"))
    }

    fn visitIfStmt(&self, expr: &IfStmts) -> Result<String, SyntaxResult> {
        let names = self.prerry("IfStmts".to_string());
        self.addLayer();
        let kind = self.prerry(format!("SyntaxKind:{:?}", SyntaxKind::OpenParenthesis));
        let con = self.parenTheSize(&"".to_string(), &[&expr.condition]);
        let kind2 = self.prerry(format!("SyntaxKind:{:?}", SyntaxKind::CloseParenthesis));

        let thanname = self.prerry("thanBranch".to_string());
        self.addLayer();
        let than = self.execute(&expr.thenBranch)?;
        self.decLayer();
        let mut _elsename = String::new();
        if let Some(_else) = &expr.elseBranch {
            _elsename = self.prerry("ElseBranch".to_string());
            self.addLayer();
            _elsename = format!("{_elsename}{}", self.execute(_else)?);
            self.decLayer();
        }
        self.decLayer();

        Ok(format!(
            "{names}{kind}{con}{kind2}{thanname}{than}{_elsename}"
        ))
    }

    fn visitWhileStmt(&self, expr: &WhileStmts) -> Result<String, SyntaxResult> {
        let names = self.prerry("WhileStmts".to_string());
        self.addLayer();
        let kind = self.prerry(format!("SyntaxKind:{:?}", SyntaxKind::OpenParenthesis));
        let con = self.parenTheSize(&"".to_string(), &[&expr.condition]);
        let kind2 = self.prerry(format!("SyntaxKind:{:?}", SyntaxKind::CloseParenthesis));

        let thanname = self.prerry("WhileBody".to_string());
        self.addLayer();
        let than = self.execute(&expr.body)?;
        self.decLayer();

        self.decLayer();

        Ok(format!("{names}{kind}{con}{kind2}{thanname}{than}"))
    }

    fn visitFunctionStmt(&self, expr: &FunctionStmts) -> Result<String, SyntaxResult> {
        let names = self.prerry("FunctionStmt".to_string());
        self.addLayer();
        let kind = self.prerry(format!("name:{}", expr.name.as_string()));

        let kind = self.prerry(format!("SyntaxKind:{:?}", SyntaxKind::OpenParenthesis));

        let mut result = String::new();
        for arg in expr.params.as_ref() {
            result = format!("{}{}", result, self.prerry(arg.as_string().to_string()));
        }

        let kind2 = self.prerry(format!("SyntaxKind:{:?}", SyntaxKind::CloseParenthesis));

        let thanname = self.prerry("Body".to_string());
        self.addLayer();
        //let than = self.execute(&expr.body)?;
        let mut than = String::new();
        for statement in expr.body.as_ref() {
            than = format!("{than}{}", self.execute(statement)?);
        }
        self.decLayer();

        self.decLayer();

        Ok(format!("{names}{kind}{result}{kind2}{thanname}{than}"))
    }

    fn visitBreakStmt(&self, expr: &BreakStmt) -> Result<String, SyntaxResult> {
        let names = self.prerry("BreakStmt".to_string());
        self.addLayer();

        let result = self.prerry(expr.token.as_string().to_string());

        self.decLayer();

        Ok(format!("{names}{result}"))
    }

    fn visitReturnStmt(&self, expr: &ReturnStmt) -> Result<String, SyntaxResult> {
        todo!()
    }
}

#[allow(non_snake_case)]
impl VisitorPrettyPrinter {
    pub fn new() -> Self {
        Self {
            //prefix:RefCell::new(String::new()),
            currentLayer: RefCell::new(0),
        }
    }
    pub fn print(&self, expr: &SyntaxExpression) -> Result<String, SyntaxResult> {
        expr.accept::<String>(self)
    }
    fn parenTheSize(&self, name: &String, exprs: &[&SyntaxExpression]) -> String {
        let mut builder = name.to_string();
        for expr in exprs {
            //let r = expr.accept::<String>(self)?;

            if let Ok(string) = expr.accept::<String>(self) {
                builder = format!("{builder}{}", string);
            }
        }

        builder
    }

    fn execute(&self, stmt: &Stmt) -> Result<String, SyntaxResult> {
        stmt.accept(self)
    }
    pub fn interpret(&self, stmts: &[Stmt]) -> bool {
        let mut hasError = false;
        for stmt in stmts {
            self.resetLayer();
            match self.execute(stmt) {
                Ok(str) => print!("{}", str),
                Err(e) => hasError = true,
            }
        }
        hasError
    }
    fn addLayer(&self) {
        *self.currentLayer.borrow_mut() += 1;
    }
    fn decLayer(&self) {
        *self.currentLayer.borrow_mut() -= 1;
    }
    fn resetLayer(&self) {
        *self.currentLayer.borrow_mut() = 0;
    }
    fn getCurrentLayer(&self) -> usize {
        *self.currentLayer.borrow()
    }
    fn prerry(&self, message: String) -> String {
        let mut tab = String::new();
        let mut count = self.getCurrentLayer();

        while count != 0 {
            tab = format!("{tab}{}", "\t");
            count -= 1;
        }
        format!("{}{}\n", tab, message)
    }
}

#[allow(non_snake_case)]
impl ExpressionVisitor<String> for VisitorPrettyPrinter {
    fn visitBinaryExpression(&self, expr: &BinaryExpression) -> Result<String, SyntaxResult> {
        let name = self.prerry("BinaryExpr".to_string());

        self.addLayer();

        let kind = self.prerry(format!("SyntaxKind:{:?}", expr.operator.kind));
        let result = self.parenTheSize(&kind.to_string(), &[&expr.left, &expr.right]);

        self.decLayer();

        Ok(format!("{name}{result}"))
    }

    fn visitGroupingExpression(&self, expr: &GroupingExpression) -> Result<String, SyntaxResult> {
        let name = self.prerry("Grouping".to_string());
        self.addLayer();
        let kind1 = self.prerry(format!("SyntaxKind:{:?}", SyntaxKind::OpenParenthesis));

        let result = self.parenTheSize(&format!("{name}{kind1}"), &[&expr.expression]);
        let kind2 = self.prerry(format!("SyntaxKind:{:?}", SyntaxKind::CloseParenthesis));
        self.decLayer();
        Ok(format!("{result}{kind2}"))
    }

    fn visitLiteralExpression(&self, expr: &LiteralExpression) -> Result<String, SyntaxResult> {
        let mut tab = String::new();
        if let Some(value) = &expr.value {
            return Ok(self.prerry(format!("LiteralExpr:{:?}", value)));
        }
        Ok(self.prerry("LiteralExpr:Nil\n".to_string()))
    }

    fn visitUnaryExpression(&self, expr: &UnaryExpression) -> Result<String, SyntaxResult> {
        let name = self.prerry("UnaryExpr".to_string());
        self.addLayer();
        let kind = self.prerry(format!("SyntaxKind:{:?}", expr.operator.kind));
        let result = self.parenTheSize(&format!("{name}{kind}"), &[&expr.right]);
        self.decLayer();
        Ok(result)
    }

    fn visitProgramExpression(&self, expr: &ProgramExpression) -> Result<String, SyntaxResult> {
        todo!()
    }

    fn visitVariableExpression(&self, expr: &VariableExpression) -> Result<String, SyntaxResult> {
        let name = self.prerry("VariableExpr".to_string());
        self.addLayer();
        let result = self.prerry(format!(
            "name:{:?}('{}')",
            expr.name.kind,
            expr.name.as_string()
        ));
        self.decLayer();

        Ok(format!("{name}{result}"))
    }

    fn visitAssignmentExpression(
        &self,
        expr: &AssignmentExpression,
    ) -> Result<String, SyntaxResult> {
        let name = self.prerry("AssignmentExpr".to_string());
        self.addLayer();
        let kind = self.prerry(format!(
            "name:{:?}('{}')",
            expr.name.kind,
            expr.name.as_string()
        ));

        let result = self.parenTheSize(&format!("{name}{kind}"), &[&expr.value]);
        self.decLayer();

        Ok(result)
    }

    fn visitLogicalExpression(&self, expr: &LogicalExpression) -> Result<String, SyntaxResult> {
        let name = self.prerry("LogicalExpr".to_string());

        self.addLayer();

        let kind = self.prerry(format!("SyntaxKind:{:?}", expr.operator.kind));
        let result = self.parenTheSize(&kind.to_string(), &[&expr.left, &expr.right]);

        self.decLayer();

        Ok(format!("{name}{result}"))
    }

    fn visitCallExpression(&self, expr: &CallExpression) -> Result<String, SyntaxResult> {
        let name = self.prerry("CallExpr".to_string());

        self.addLayer();

        let kind = self.prerry(format!("SyntaxKind:{:?}", expr.paren.kind));
        let mut result = String::new();
        for arg in &expr.arguments {
            result = format!("{}{}", result, self.parenTheSize(&kind.to_string(), &[arg]))
        }

        self.decLayer();

        Ok(format!("{name}{kind}{result}"))
    }
}
